"""
邮件模板服务
处理邮件模板的CRUD操作、变量提取、模板渲染等业务逻辑
"""

import re
import json
import markdown
from typing import List, Optional, Dict, Any, Set
from sqlalchemy.orm import Session
from sqlalchemy import func, or_
from fastapi import HTTPException, status
from datetime import datetime, timedelta
from jinja2 import Template, Environment, meta, TemplateSyntaxError

from models.email_template import EmailTemplate
from schemas.email_template import (
    EmailTemplateCreate, EmailTemplateUpdate, EmailTemplateResponse, EmailTemplateList,
    TemplatePreviewRequest, TemplatePreviewResponse, TemplateVariableExtractRequest,
    TemplateVariableExtractResponse, TemplateStatistics, TemplateCloneRequest,
    TemplateType, TemplateCategory
)


class EmailTemplateService:
    """邮件模板服务类"""
    
    @staticmethod
    def create_email_template(db: Session, template_data: EmailTemplateCreate, user_id: int) -> EmailTemplate:
        """创建邮件模板"""
        # 检查名称是否已存在
        existing = db.query(EmailTemplate).filter(
            EmailTemplate.name == template_data.name,
            EmailTemplate.user_id == user_id
        ).first()
        
        if existing:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="模板名称已存在"
            )
        
        # 自动提取模板变量
        variables = EmailTemplateService._extract_template_variables(
            template_data.content, 
            template_data.subject
        )
        
        # 创建邮件模板
        db_template = EmailTemplate(
            name=template_data.name,
            subject=template_data.subject,
            content=template_data.content,
            template_type=template_data.template_type.value,
            category=template_data.category.value,
            description=template_data.description,
            variables=variables,
            is_active=template_data.is_active,
            user_id=user_id
        )
        
        db.add(db_template)
        db.commit()
        db.refresh(db_template)
        return db_template
    
    @staticmethod
    def get_email_templates(
        db: Session, 
        user_id: int, 
        page: int = 1, 
        size: int = 10,
        search: Optional[str] = None,
        category: Optional[TemplateCategory] = None,
        template_type: Optional[TemplateType] = None,
        active_only: bool = False
    ) -> EmailTemplateList:
        """获取邮件模板列表"""
        query = db.query(EmailTemplate).filter(EmailTemplate.user_id == user_id)
        
        # 搜索过滤
        if search:
            search_pattern = f"%{search}%"
            query = query.filter(
                or_(
                    EmailTemplate.name.like(search_pattern),
                    EmailTemplate.subject.like(search_pattern),
                    EmailTemplate.description.like(search_pattern)
                )
            )
        
        # 分类过滤
        if category:
            query = query.filter(EmailTemplate.category == category.value)
        
        # 类型过滤
        if template_type:
            query = query.filter(EmailTemplate.template_type == template_type.value)
        
        # 状态过滤
        if active_only:
            query = query.filter(EmailTemplate.is_active == True)
        
        # 总数
        total = query.count()
        
        # 分页
        items = query.order_by(EmailTemplate.created_at.desc()).offset((page - 1) * size).limit(size).all()
        
        # 计算总页数
        pages = (total + size - 1) // size
        
        return EmailTemplateList(
            items=[EmailTemplateResponse.from_orm(item) for item in items],
            total=total,
            page=page,
            size=size,
            pages=pages
        )
    
    @staticmethod
    def get_email_template(db: Session, template_id: int, user_id: int) -> Optional[EmailTemplate]:
        """获取单个邮件模板"""
        return db.query(EmailTemplate).filter(
            EmailTemplate.id == template_id,
            EmailTemplate.user_id == user_id
        ).first()
    
    @staticmethod
    def update_email_template(
        db: Session, 
        template_id: int, 
        template_data: EmailTemplateUpdate, 
        user_id: int
    ) -> Optional[EmailTemplate]:
        """更新邮件模板"""
        db_template = EmailTemplateService.get_email_template(db, template_id, user_id)
        if not db_template:
            return None
        
        # 检查名称是否已存在（排除自己）
        if template_data.name:
            existing = db.query(EmailTemplate).filter(
                EmailTemplate.name == template_data.name,
                EmailTemplate.user_id == user_id,
                EmailTemplate.id != template_id
            ).first()
            
            if existing:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="模板名称已存在"
                )
        
        # 更新字段
        update_data = template_data.dict(exclude_unset=True)
        for field, value in update_data.items():
            if field in ['template_type', 'category'] and value:
                setattr(db_template, field, value.value)
            else:
                setattr(db_template, field, value)
        
        # 如果内容或主题有更新，重新提取变量
        if template_data.content or template_data.subject:
            content = template_data.content or db_template.content
            subject = template_data.subject or db_template.subject
            variables = EmailTemplateService._extract_template_variables(content, subject)
            db_template.variables = variables
        
        db.commit()
        db.refresh(db_template)
        return db_template
    
    @staticmethod
    def delete_email_template(db: Session, template_id: int, user_id: int) -> bool:
        """删除邮件模板"""
        db_template = EmailTemplateService.get_email_template(db, template_id, user_id)
        if not db_template:
            return False
        
        db.delete(db_template)
        db.commit()
        return True
    
    @staticmethod
    def toggle_template_status(db: Session, template_id: int, user_id: int) -> Optional[EmailTemplate]:
        """切换模板启用状态"""
        db_template = EmailTemplateService.get_email_template(db, template_id, user_id)
        if not db_template:
            return None
        
        db_template.is_active = not db_template.is_active
        db.commit()
        db.refresh(db_template)
        return db_template

    @staticmethod
    def preview_template(
        db: Session,
        preview_request: TemplatePreviewRequest,
        user_id: int
    ) -> TemplatePreviewResponse:
        """预览模板"""
        # 获取模板内容
        if preview_request.template_id:
            template = EmailTemplateService.get_email_template(db, preview_request.template_id, user_id)
            if not template:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="模板不存在"
                )
            subject = template.subject
            content = template.content
            template_type = TemplateType(template.template_type)
        else:
            subject = preview_request.subject or ""
            content = preview_request.content or ""
            template_type = preview_request.template_type

        # 渲染模板
        try:
            rendered_subject, rendered_content, html_content = EmailTemplateService._render_template(
                subject, content, template_type, preview_request.variables or {}
            )

            # 提取使用的变量
            variables_used = EmailTemplateService._extract_template_variables(content, subject)

            # 找出缺失的变量
            provided_vars = set(preview_request.variables.keys()) if preview_request.variables else set()
            missing_variables = [var for var in variables_used if var not in provided_vars]

            return TemplatePreviewResponse(
                rendered_subject=rendered_subject,
                rendered_content=rendered_content,
                html_content=html_content,
                variables_used=variables_used,
                missing_variables=missing_variables
            )
        except Exception as e:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"模板渲染失败: {str(e)}"
            )

    @staticmethod
    def extract_template_variables(extract_request: TemplateVariableExtractRequest) -> TemplateVariableExtractResponse:
        """提取模板变量"""
        content_variables = EmailTemplateService._extract_template_variables(extract_request.content)
        subject_variables = []

        if extract_request.subject:
            subject_variables = EmailTemplateService._extract_template_variables(extract_request.subject)

        # 合并所有变量
        all_variables = list(set(content_variables + subject_variables))

        return TemplateVariableExtractResponse(
            variables=all_variables,
            subject_variables=subject_variables,
            content_variables=content_variables
        )

    @staticmethod
    def clone_template(db: Session, clone_request: TemplateCloneRequest, user_id: int) -> EmailTemplate:
        """克隆模板"""
        # 获取原模板
        original_template = EmailTemplateService.get_email_template(db, clone_request.template_id, user_id)
        if not original_template:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="原模板不存在"
            )

        # 检查新名称是否已存在
        existing = db.query(EmailTemplate).filter(
            EmailTemplate.name == clone_request.new_name,
            EmailTemplate.user_id == user_id
        ).first()

        if existing:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="模板名称已存在"
            )

        # 创建新模板
        new_template = EmailTemplate(
            name=clone_request.new_name,
            subject=original_template.subject,
            content=original_template.content,
            template_type=original_template.template_type,
            category=original_template.category,
            description=f"克隆自: {original_template.name}",
            variables=original_template.variables,
            is_active=True,
            user_id=user_id
        )

        db.add(new_template)
        db.commit()
        db.refresh(new_template)
        return new_template

    @staticmethod
    def get_template_statistics(db: Session, user_id: int) -> TemplateStatistics:
        """获取模板统计信息"""
        # 总数统计
        total = db.query(EmailTemplate).filter(EmailTemplate.user_id == user_id).count()

        # 启用状态统计
        active = db.query(EmailTemplate).filter(
            EmailTemplate.user_id == user_id,
            EmailTemplate.is_active == True
        ).count()

        # 按分类统计
        category_stats = db.query(
            EmailTemplate.category,
            func.count(EmailTemplate.id).label('count')
        ).filter(EmailTemplate.user_id == user_id).group_by(EmailTemplate.category).all()

        by_category = {item.category: item.count for item in category_stats}

        # 按类型统计
        type_stats = db.query(
            EmailTemplate.template_type,
            func.count(EmailTemplate.id).label('count')
        ).filter(EmailTemplate.user_id == user_id).group_by(EmailTemplate.template_type).all()

        by_type = {item.template_type: item.count for item in type_stats}

        # 最近7天新增
        seven_days_ago = datetime.now() - timedelta(days=7)
        recent_added = db.query(EmailTemplate).filter(
            EmailTemplate.user_id == user_id,
            EmailTemplate.created_at >= seven_days_ago
        ).count()

        return TemplateStatistics(
            total=total,
            active=active,
            by_category=by_category,
            by_type=by_type,
            recent_added=recent_added
        )

    @staticmethod
    def _extract_template_variables(content: str, subject: str = "") -> List[str]:
        """提取模板中的变量"""
        variables = set()

        # 使用Jinja2环境提取变量
        env = Environment()
        try:
            # 提取内容中的变量
            ast = env.parse(content)
            content_vars = meta.find_undeclared_variables(ast)
            variables.update(content_vars)

            # 提取主题中的变量
            if subject:
                ast = env.parse(subject)
                subject_vars = meta.find_undeclared_variables(ast)
                variables.update(subject_vars)
        except TemplateSyntaxError:
            # 如果Jinja2解析失败，使用正则表达式
            pattern = r'\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}'
            content_vars = re.findall(pattern, content)
            subject_vars = re.findall(pattern, subject) if subject else []
            variables.update(content_vars + subject_vars)

        return sorted(list(variables))

    @staticmethod
    def _render_template(
        subject: str,
        content: str,
        template_type: TemplateType,
        variables: Dict[str, Any]
    ) -> tuple[str, str, str]:
        """渲染模板"""
        env = Environment()

        try:
            # 渲染主题
            subject_template = env.from_string(subject)
            rendered_subject = subject_template.render(**variables)

            # 渲染内容
            content_template = env.from_string(content)
            rendered_content = content_template.render(**variables)

            # 根据模板类型生成HTML内容
            if template_type == TemplateType.MARKDOWN:
                # Markdown转HTML
                html_content = markdown.markdown(
                    rendered_content,
                    extensions=['extra', 'codehilite', 'toc']
                )
            elif template_type == TemplateType.PLAIN_TEXT:
                # 纯文本转HTML（保留换行）
                html_content = rendered_content.replace('\n', '<br>')
            else:
                # HTML内容直接使用
                html_content = rendered_content

            return rendered_subject, rendered_content, html_content

        except Exception as e:
            raise Exception(f"模板渲染失败: {str(e)}")

    @staticmethod
    def get_active_templates(db: Session, user_id: int) -> List[EmailTemplate]:
        """获取用户的所有启用模板"""
        return db.query(EmailTemplate).filter(
            EmailTemplate.user_id == user_id,
            EmailTemplate.is_active == True
        ).order_by(EmailTemplate.created_at.desc()).all()

    @staticmethod
    def get_templates_by_category(db: Session, user_id: int, category: TemplateCategory) -> List[EmailTemplate]:
        """根据分类获取模板"""
        return db.query(EmailTemplate).filter(
            EmailTemplate.user_id == user_id,
            EmailTemplate.category == category.value,
            EmailTemplate.is_active == True
        ).order_by(EmailTemplate.created_at.desc()).all()

    @staticmethod
    def search_templates(db: Session, user_id: int, keyword: str, limit: int = 10) -> List[EmailTemplate]:
        """搜索模板（用于自动完成等场景）"""
        search_pattern = f"%{keyword}%"
        return db.query(EmailTemplate).filter(
            EmailTemplate.user_id == user_id,
            EmailTemplate.is_active == True,
            or_(
                EmailTemplate.name.like(search_pattern),
                EmailTemplate.subject.like(search_pattern)
            )
        ).limit(limit).all()
